package com.anlu.concurrent.ch08b.service.question;
import com.anlu.concurrent.ch08b.assist.*;
import com.anlu.concurrent.ch08b.service.question.SingleQstService;
import com.anlu.concurrent.ch08b.vo.*;

import java.util.concurrent.*;

/**
 *并发处理题目的服务
 */
public class ParallerQstService {

    /**
     *已处理题目的缓存
     */
    private static ConcurrentHashMap<Integer,QuestionInCacheVo> questionCache = new ConcurrentHashMap<>();

    /**
     *正在处理题目的缓存
     */
    private static ConcurrentHashMap<Integer, Future<QuestionInCacheVo>> processingQuestionCache = new ConcurrentHashMap<>();

    //创建线程池
    private static ExecutorService makeQuestionService = Executors.newFixedThreadPool(Consts.CPU_COUNT*2);

    /**
     * 开始生产题目
     * @param questionId 题目的ID
     * @return
     */
    public static TaskResultVo makeQuestion(Integer questionId){
         QuestionInCacheVo qstCacheVo = questionCache.get(questionId);
         if(null==qstCacheVo){
             System.out.println("......题目["+questionId+"]在缓存中不存在，"
                     + "准备启动任务.");
            return new TaskResultVo(getQstFuture(questionId));
         }else{
            //拿摘要
            String questionSha =SL_QuestionBank.getSha(questionId);
            if(questionSha.equals(qstCacheVo.getQuestionSha())){
                System.out.println("......题目["+questionId+"]在缓存中已存在，且未变化.");
                return new TaskResultVo(qstCacheVo.getQuestionDetail());
            }else {
                System.out.println("......题目["+questionId+"]在缓存中已存在，"
                        + "但是发生了变化，更新缓冲.");
                return new TaskResultVo(getQstFuture(questionId));
            }
         }
    }

    private static Future<QuestionInCacheVo> getQstFuture(Integer questionId){
        //从缓存中获取 要执行的任务
        Future<QuestionInCacheVo> questionInCacheVoFuture = processingQuestionCache.get(questionId);
        try{
            if(questionInCacheVoFuture==null){
                //从数据库中获取题目
                QuestionInDBVo qstDbVo = SL_QuestionBank.getQuetion(questionId);
                //创建一个任务
                QuestionTask questionTask = new QuestionTask(qstDbVo,questionId);

                FutureTask<QuestionInCacheVo> ft = new FutureTask<>(questionTask);

                questionInCacheVoFuture= processingQuestionCache.putIfAbsent(questionId,
                        ft);
                if(questionInCacheVoFuture==null) {
                    //先在map中占位
                    questionInCacheVoFuture = ft;
                    makeQuestionService.execute(ft);
                    System.out.println("成功启动了题目["+questionId+"]的计算任务，请等待完成>>>>>>>>");
                }else {
                    System.out.println("<<<<<<<<<<<有其他线程刚刚启动了题目["+questionId
                            +"]的计算任务，本任务无需开启！");
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }

        return questionInCacheVoFuture;
    }



    //解析题目的任务类
    private static class QuestionTask implements Callable<QuestionInCacheVo> {
        private QuestionInDBVo qstDbVo;
        private Integer questionId;
        public QuestionTask(QuestionInDBVo qstDbVo, Integer questionId) {
            super();
            this.qstDbVo = qstDbVo;
            this.questionId = questionId;
        }

        @Override
        public QuestionInCacheVo call() throws Exception {
            try{
                String qstDetail = BaseQuestionProcessor.makeQuestion(questionId,
                        SL_QuestionBank.getQuetion(questionId).getDetail());
                String questionSha = qstDbVo.getSha();
                QuestionInCacheVo qstCache = new QuestionInCacheVo(qstDetail, questionSha);
                questionCache.put(questionId, qstCache);
                return qstCache;
            }finally {
                //不管生成题目的任务正常与否，这个任务都要从正在处理题目的缓存中移除
                processingQuestionCache.remove(questionId);
            }
        }
    }

}
